package ms.sudoku.technique;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import ms.sudoku.PuzzleState;
import ms.sudoku.util.IntSet;

import common.Sudokus;

public final class NakedSingleTechnique extends EliminationTechnique {
	public NakedSingleTechnique() {
	}

	public long getDifficultyLevel() {
		return 2;
	}

	public boolean execute(PuzzleState state, boolean exitEarlyWhenSoleFound, IntSet[][] possibleNumbers,
			AtomicInteger numberOfChanges, AtomicBoolean exitedEarly) {
		numberOfChanges.set(0);
		exitedEarly.set(false);

		int gridSize = state.getGridSize();
		int boxSize = state.getBoxSize();

		// Eliminate impossible numbers based on numbers already set in the grid
		for (int row = 0; row < gridSize; row++) {
			for (int col = 0; col < gridSize; col++) {
				int valueToEliminate = state.get(row, col);
				/*
				 * If this cell has a value, we use it to eliminate numbers in
				 * other cells
				 */
				if (Sudokus.notEmpty(valueToEliminate)) {
					// eliminate numbers in same row
					for (int y = 0; y < gridSize; y++) {
						if (possibleNumbers[row][y].contains(valueToEliminate)) {
							numberOfChanges.incrementAndGet();
							possibleNumbers[row][y].remove(valueToEliminate);
						}

					}
					// eliminate numbers in same column
					for (int x = 0; x < gridSize; x++) {
						if (possibleNumbers[x][col].contains(valueToEliminate)) {
							numberOfChanges.incrementAndGet();
							possibleNumbers[x][col].remove(valueToEliminate);
						}

					}
					// eliminate numbers in same box
					int boxStartX = (row / boxSize) * boxSize;
					int boxStartY = (col / boxSize) * boxSize;
					for (int x = boxStartX; x < boxStartX + boxSize; x++) {
						for (int y = boxStartY; y < boxStartY + boxSize; y++) {
							if (possibleNumbers[x][y].contains(valueToEliminate)) {
								numberOfChanges.incrementAndGet();
								possibleNumbers[x][y].remove(valueToEliminate);
							}
						}
					}
				}
			}
		}
		return false;
	}
}
